package com.flyan.game.motafx.core.algorithm;

import com.almasb.fxgl.entity.Entity;
import com.flyan.game.motafx.component.character.BraveComponent;
import com.flyan.game.motafx.component.npc.NpcComponent;
import com.flyan.game.motafx.component.terrain.TerrainComponent;
import com.flyan.game.motafx.core.enums.DirEnum;
import com.flyan.game.motafx.core.enums.EntityClassifyEnum;
import com.flyan.game.motafx.core.enums.EntityTypeEnum;
import com.flyan.game.motafx.core.enums.ZLayerEnum;
import com.flyan.game.motafx.core.map.FloorMap;
import com.flyan.game.motafx.core.map.MapPosition;
import com.flyan.game.motafx.core.map.MapPositionEntityInfo;
import com.flyan.game.motafx.core.util.console.ConsoleUtils;
import com.flyan.game.motafx.core.util.entity.EntityUtils;
import com.flyan.game.motafx.entity.terrain.TerrainEntityInfo;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 勇士移动算法
 *
 * @author flyan
 * @version 1.0
 * @email flyan_by_chenu@sina.com
 * @since 2025/2/5
 */
public final class BraveMoveAlgorithm {

    /**
     * 勇士所处楼层地图
     */
    private FloorMap floor;

    /**
     * 勇士所处位置
     */
    private MapPosition bravePos;

    /**
     * 勇士组件
     */
    private BraveComponent brave;

    public BraveMoveAlgorithm(FloorMap floor) {
        setFloor(floor);
    }

    public BraveMoveAlgorithm() {
        this(null);
    }

    public BraveMoveAlgorithm setFloor(FloorMap floor) {
        if (floor != null) {
            this.floor = floor;
            bravePos = locateBravePositionFromMap(floor);
            MapPositionEntityInfo bravePositionInfo = floor.getPositionEntityInfo(bravePos);
            Entity braveEntity = bravePositionInfo.getByZIndex(EntityTypeEnum.CHARACTER_BRAVE.getZIndex().getIndex());
            brave = braveEntity.getComponent(BraveComponent.class);
        }
        return this;
    }

    /**
     * 勇士移动一步
     *
     * @param moveDir 移动方向
     * @return 移动是否成功
     */
    public boolean moveOneStep(DirEnum moveDir) {
        switch (moveDir) {
            case UP -> {
                return move(Collections.singletonList(
                        new MapPosition(bravePos.row() - 1, bravePos.col())));
            }
            case DOWN -> {
                return move(Collections.singletonList(
                        new MapPosition(bravePos.row() + 1, bravePos.col())));
            }
            case LEFT -> {
                return move(Collections.singletonList(
                        new MapPosition(bravePos.row(), bravePos.col() - 1)));
            }
            case RIGHT -> {
                return move(Collections.singletonList(
                        new MapPosition(bravePos.row(), bravePos.col() + 1)));
            }
        }
        return false;
    }

    public boolean checkMoveOneStep(DirEnum moveDir) {
        switch (moveDir) {
            case UP -> {
                return checkMovePath(Collections.singletonList(
                        new MapPosition(bravePos.row() - 1, bravePos.col())));
            }
            case DOWN -> {
                return checkMovePath(Collections.singletonList(
                        new MapPosition(bravePos.row() + 1, bravePos.col())));
            }
            case LEFT -> {
                return checkMovePath(Collections.singletonList(
                        new MapPosition(bravePos.row(), bravePos.col() - 1)));
            }
            case RIGHT -> {
                return checkMovePath(Collections.singletonList(
                        new MapPosition(bravePos.row(), bravePos.col() + 1)));
            }
        }
        return false;
    }

    /**
     * 移动
     *
     * @param path 移动路径，第一个位置必须是勇士起始位置的邻格
     * @return 移动是否成功
     */
    public boolean move(List<MapPosition> path) {
        /* 检查是否可移动 */
        if (!checkMovePath(path)) {
            return false;
        }

        /* 更新勇士位置 */
        floor.updateBravePosition(path.getLast());
        bravePos = path.getLast();

        return true;
    }

    /**
     * 检查移动路径是否可达
     *
     * @param path 移动路径，第一个位置必须是勇士起始位置的邻格
     * @return 是否可移动到目标为止
     */
    public boolean checkMovePath(List<MapPosition> path) {
        /* 不做移动 */
        if (path.isEmpty()) {
            return false;
        }

        /* 所有位置都必须正确 */
        for (MapPosition pos : path) {
            if (!pos.isCorrect()) {
//                ConsoleUtils.println("不可移动：错误的位置坐标");
                return false;
            }
        }

        /* 首先第一个移动位置必须是勇士相邻格 */
        var first = path.getFirst();
        if (!bravePos.isAdjacent(first)) {
            ConsoleUtils.println("不可移动：不是勇士相邻的位置");
            return false;
        }

        /* 检查每步低图、中图层是否存在障碍 */
        for (int i = 0; i < path.size(); i++) {
            MapPosition pos = path.get(i);
            boolean isEnd = i == path.size() - 1;

            MapPositionEntityInfo entityInfo = floor.getPositionEntityInfo(pos);
            Entity low = entityInfo.getByZIndex(ZLayerEnum.LOW.getIndex());
            boolean canGo = true;

            /* 最低图层不存在任何实体，不能踏空行走~ */
            if (low == null) {
                canGo = false;
            }

            /*
                必须是可行走的位置，可行走位置需要满足如下条件
                1、若当前不是最后一步，则每个图层的实体，不能是地形；若是地形实体，则不能是阻碍地形
                1、若是最后一步，则每个图层的实体，不能是阻碍地形
             */
            for (ZLayerEnum z : ZLayerEnum.values()) {
                if (canGo) {
                    Entity entity = entityInfo.getByZIndex(z.getIndex());
                    if (!isEnd) {
                        if (entity != null) {
                            EntityTypeEnum type = (EntityTypeEnum) entity.getType();
                            if (type.getClassify() == EntityClassifyEnum.TERRAIN) {
                                /* 若是地形实体，则不能是阻碍地形； */
                                TerrainEntityInfo info = EntityUtils.getEntityInfo(entity, TerrainEntityInfo.class);
                                if (info.isBlock()) {
                                    ConsoleUtils.println("不可移动：前方物体为（%s）".formatted(type.name()));
                                    canGo = false;
                                }
                            } else {
                                /* 不能是地形（一般为可交互的npc，物品等等） */
                                ConsoleUtils.println("不可移动：前方物体为（%s）".formatted(type.name()));
                                canGo = false;
                            }
                        }
                    } else {
                        if (entity != null) {
                            EntityTypeEnum type = (EntityTypeEnum) entity.getType();
                            if (type.getClassify() == EntityClassifyEnum.TERRAIN) {
                                TerrainEntityInfo info = EntityUtils.getEntityInfo(entity, TerrainEntityInfo.class);
                                if (info.isBlock()) {
                                    if (!info.isCanDestroy()) {
//                                        ConsoleUtils.println("不可移动：前方物体为不可破坏实体（%s）".formatted(type.name()));
                                        canGo = false;
                                    } else {
                                        TerrainComponent terrainComponent = entity.getComponent(TerrainComponent.class);
                                        if (info.isCanDestroy() && !terrainComponent.collisionIsCanDestroy(brave.getEntity())) {
//                                            ConsoleUtils.println("不可移动：前方物体为可破坏实体（%s）".formatted(type.name()));
                                            canGo = false;
                                        }
                                    }
                                }
                            } else if (type.getClassify() == EntityClassifyEnum.MONSTER) {
                                BattleAlgorithm battleAlgorithm = new BattleAlgorithm(
                                        new Battler(brave.getEntity()), new Battler(entity));
                                BattleResult attackResult = battleAlgorithm.getBattleResult();
                                if (!attackResult.isCanBatter()) {
                                    ConsoleUtils.println(attackResult.getNotCanBatterReason());
                                    canGo = false;
                                } else if (!attackResult.winnerIsAttacker()) {
                                    ConsoleUtils.println("不可战斗：你打不过此怪物！");
                                    canGo = false;
                                }
                            } else if (type.getClassify() == EntityClassifyEnum.NPC) {
                                /* 不许走！和 npc 交互 */
                                entity.getComponent(NpcComponent.class).interact(brave.getEntity());
                                canGo = false;
                            }
                        }
                    }
                }
            }

            if (!canGo) {
                return false;
            }
        }

        return true;
    }

    /**
     * 从地图上定位勇士位置
     *
     * @param map   地图
     * @return      勇士位置
     */
    public MapPosition locateBravePositionFromMap(FloorMap map) {
        AtomicReference<MapPosition> findAns = new AtomicReference<>();
        map.traverseMap((pos, entityType, entity) -> {
            if (entityType == EntityTypeEnum.CHARACTER_BRAVE) {
                findAns.set(pos);
                return false;
            }
            return true;
        });
        return findAns.get();
    }

}
